﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace RectBar
{
    public partial class RectCBarPanel : UserControl
    {

        /// <summary>
        /// 比例改变，需要重绘
        /// </summary>
        public static event Action RatioChanged;

        public static int _pxRatioTime = 4;//默认比例

        /// <summary>
        /// 像素与时间的比率，即： PxRatioTime 个像素代表1秒
        /// </summary>
        public static int PxRatioTime
        {
            get { return _pxRatioTime; }
            set
            {
                _pxRatioTime = value;
                if (RatioChanged != null)
                {
                    RatioChanged();
                }
            }
        }

        public static int _pxRatioDistance = 1;

        /// <summary>
        /// 像素与距离的比率，即： PxRatioDistance 个像素代表1米
        /// </summary>
        public static int PxRatioDistance
        {
            get { return _pxRatioDistance; }
            set
            {
                _pxRatioDistance = value;
                if (RatioChanged != null)
                {
                    RatioChanged();
                }
            }
        }

        private Graphics panelGraphics;
        public RectCBarPanel()
        {
            InitializeComponent();
            panelGraphics = CreateGraphics();
            InitCBar();
            RectCBarPanel.RatioChanged += this.Invalidate;
        }

        /// <summary>
        /// Bar进度条左边界
        /// </summary>
        public int BarMinXlocation
        {
            get { return 200; }
        }

        /// <summary>
        /// Bar进度条右边界
        /// </summary>
        public int BarMaxXlocation
        {
            get { return this.Width + 500; }
        }

        /// <summary>
        /// 标题鼠标悬浮提示
        /// </summary>
        ToolTip titleTip = new ToolTip();

        /// <summary>
        /// 保存各路口距离差值的数组
        /// </summary>
        List<int> distanceOffsetList = new List<int>(); 

        /// <summary>
        /// 保存所有添加的路口色条
        /// </summary>
        List<RectCBar> barList = new List<RectCBar>(); 

        public void InitCBar()
        {
            CreateContorls();

            RectCBar baseBar = CreateBar(null, 0, "1#中文字符", 14, 16, 17, 18); 
            barList.Add(baseBar);
            barList.Add(CreateBar(baseBar, 36, "2#asdfghjklqwe"));
            barList.Add(CreateBar(baseBar, 77, "3#asdfghjklqwe"));
            barList.Add(CreateBar(baseBar, 120, "4#asdfghjklqwe"));
            barList.Add(CreateBar(baseBar, 167, "5#asdfghjklqwe"));
            barList.Add(CreateBar(baseBar, 220, "6#asdfghjklqwe"));
//             barList.Add(CreateBar(baseBar, 367, "7#asdfghjklqwe"));
//             barList.Add(CreateBar(baseBar, 520, "8#asdfghjklqwe"));
//             barList.Add(CreateBar(baseBar, 667, "9#asdfghjklqwe"));
        }

        /// <summary>
        /// 创建时间条
        /// </summary>
        /// <param name="src">copy的源，可为空</param>
        /// <param name="distance">相对初始路口的距离</param>
        /// <param name="lbTitle">标题</param>
        /// <param name="eachBarTimeLength">每个小块的时间长度</param>
        /// <returns></returns>
        private RectCBar CreateBar(RectCBar src, int distance, string lbTitle, params int[] eachBarTimeLength)
        {
            // 距离计算
            int yLocation = 80 + distance*PxRatioDistance;

            if (yLocation > this.Height)
            {
                this.Height = yLocation + 100;
                this.Invalidate();
            }

            int maxTimePx = (yLocation/10 + 150)*PxRatioTime;
            if (maxTimePx > this.Width)
            {
                this.Width = maxTimePx + 10;
                this.Invalidate();
            }

            if (distance < 35)
            {
                PxRatioDistance = 2;
            }

            // 加入列表
            distanceOffsetList.Add(distance);

            // Bar
            RectCBar bar;
            bar = src == null ? new RectCBar() : src.CopyCBar();

            foreach (int length in eachBarTimeLength)
            {
                bar.EachBarTimeLength.Add(length);
            }

            bar.MinXlocation = BarMinXlocation;
            bar.MaxXlocation = BarMaxXlocation;
            this.Controls.Add(bar);
            bar.Location = new Point(BarMinXlocation + 1, yLocation);

            Func<int> getDistance = () => { return ((bar.Location.X - 200)/PxRatioTime); };

            // label tip
            Label lbTip = new Label(); // 在Bar左下角显示距离
            this.Controls.Add(lbTip);
            lbTip.Height = 10;
            lbTip.Location = new Point(bar.Location.X, bar.Location.Y - lbTip.Height);
            lbTip.Text = distance.ToString();

            bar.LocationMoved += (i, i1) =>
            {
                lbTip.Location = new Point(bar.Location.X, bar.Location.Y - lbTip.Height);
                lbTip.Text = getDistance().ToString();
                this.Invalidate();           
            };

            // Label
            Label title = new Label() {Text = lbTitle};
            this.Controls.Add(title);
            title.Width = 140;
            title.Height = 22;
            title.TextAlign = ContentAlignment.MiddleRight;
            //title.RightToLeft = RightToLeft.Yes;
            title.Location = new Point(0,yLocation);
            titleTip.SetToolTip(title,title.Text);

            // TextBox
            TextBox text = new TextBox
            {
                Text = getDistance().ToString(),
                Width = 25
            };
            bar.LocationMoved += (x, y) =>
            {
                text.Text = getDistance().ToString();
            };

            Action changeBarLocByText = () =>
            {
                int timeValue;
                if (int.TryParse(text.Text, out timeValue))
                {
                    bar.Location = new Point(200 + timeValue*PxRatioTime, yLocation);
                    this.Invalidate();
                }
            };

            RectCBarPanel.RatioChanged += () =>
            {
                //text.Text = ((bar.Location.X - 200)/PxRatioTime).ToString();
                changeBarLocByText();
            };
            text.TextChanged += (sender, args) =>
            {
                changeBarLocByText();
            };

            this.Controls.Add(text);
            text.Location = new Point(140,yLocation);

            return bar;
        }

        private void CreateContorls()
        {
            Label distanceLb = new Label { Text = "距\n离\n(米)" };
            this.Controls.Add(distanceLb);
            distanceLb.Width = 29;
            distanceLb.Height = 45;  
            distanceLb.TextAlign = ContentAlignment.TopCenter;
            distanceLb.Location = new Point(160, 32);

            Label timeOffsetLb = new Label { Text = "时间间隔(秒)" };
            this.Controls.Add(timeOffsetLb);
            timeOffsetLb.Height = 15;
            timeOffsetLb.Location = new Point(200, 10);
        }


        /// <summary>
        /// 画坐标
        /// </summary>
        private void DrawAxis()
        {
            Point axisOrigin = new Point(195,30);

            Point buttom = new Point(195,Height);
            Point right = new Point(Width,30);

            Pen pen = new Pen(Color.Black,2);

            panelGraphics.DrawLine(pen,axisOrigin,buttom);
            panelGraphics.DrawLine(pen,axisOrigin,right);

        }


        /// <summary>
        /// 画标尺
        /// </summary>
        private void DrawRuler()
        {
            // 零刻度
            DrawSingleScale(true, 0);
            DrawSingleScale(false, 0);

            // 时间刻度
            for (int i = 1; i < 50; i++)
            {
                DrawSingleScale(true, i*20);
            }
            
            // 距离刻度
//             for (int i = 1; i < 50; i++) //等距离画刻度
//             {
//                 DrawSingleScale(false, i*100);
//             }
            foreach (int distanceOffset in distanceOffsetList) //根据实际距离偏差画刻度
            {
                DrawSingleScale(false, distanceOffset);
            }
        }

        /// <summary>
        /// 获取单个刻度的坐标
        /// </summary>
        /// <param name="leftToRight"></param>
        /// <param name="number"></param>
        /// <returns></returns>
        private Point GetSingleScaleLocation(bool leftToRight, int number)
        {
            if (leftToRight)
            {
                return new Point(200 + number*PxRatioTime, 30); // 零刻度起点为 200
            }
            return new Point(195, 80 + number*PxRatioDistance); // 零刻度起点为 80
        }

        /// <summary>
        /// 画单个的刻度,number：时间或者距离的实际值
        /// </summary>
        private void DrawSingleScale(bool leftToRight,int number)
        {

            Point originPoint = GetSingleScaleLocation(leftToRight, number);

            // 标尺刻度
            Point endPoint = leftToRight ? new Point(originPoint.X, originPoint.Y + 5) : new Point(originPoint.X - 5, originPoint.Y);
            Point fongPoint;
            if (number == 0)
            {
                fongPoint  = leftToRight ? new Point(originPoint.X - 5, originPoint.Y + 8) : new Point(originPoint.X - 15, originPoint.Y + 2);
            }
            else
            {
                fongPoint = leftToRight ? new Point(originPoint.X - 10, originPoint.Y + 8) : new Point(originPoint.X - 25, originPoint.Y + 2);
            }

            Pen pen = new Pen(Color.Black,2);
            panelGraphics.DrawLine(pen,originPoint,endPoint);

            // 刻度文字

            GraphicsPath fontPath = new GraphicsPath();    
            fontPath.AddString(number.ToString(), new FontFamily("Arial"), (int)FontStyle.Bold, 12, fongPoint, StringFormat.GenericDefault);
//             Region rgFont = new Region();
//             rgFont.MakeEmpty();
//             rgFont.Union(fontPath);
            panelGraphics.FillPath(Brushes.Black,fontPath);

        }

        /// <summary>
        /// 画连接线
        /// </summary>
        /// <param name="bar1"></param>
        /// <param name="bar2"></param>
        private void DrawLinkLine(RectCBar bar1,RectCBar bar2)
        {
            Point start = new Point(bar1.Location.X, bar1.Location.Y + bar1.Height/2);
            Point end = new Point(bar2.Location.X, bar2.Location.Y + bar2.Height / 2);
            
            Pen pen = new Pen(Color.SpringGreen, 2);

            panelGraphics.DrawLine(pen, start, end);
        }

        private void RectCBarPanel_Paint(object sender, PaintEventArgs e)
        {
            panelGraphics = CreateGraphics();
            DrawAxis();
            DrawRuler();
            for (int i = 0; i < barList.Count-1; i++)
            {
                DrawLinkLine(barList[i], barList[i + 1]);
            }
        }

    }
}
